package org.shj.thread.book1.filesize;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * 当子目录较多时，会抛出Timeout exception。
 * 原因：上层目录提交任务后会占用线程，而其会等待下层子目录返回结果。当子目录数超
 *       过线程池大小时，上层目录的统计在等待下层目录的统计结果，而下层目录的统计任务
 *       则在等待可用线程，这样就造成了隐性 的死锁。
 * 
 * @author Administrator
 *
 */
public class NaiveConcurrentTotalFileSize {

	private long getTotalSizeOfFilesInDir(final ExecutorService service, File file) throws Exception{
		if(file.isFile())
			return file.length();
		
		long total = 0;
		File[] children = file.listFiles();
		if(children != null){
			List<Future<Long>> partials = new ArrayList<>();
			for(final File child : children){
				partials.add(service.submit(new Callable<Long>(){
					public Long call() throws Exception{
						return getTotalSizeOfFilesInDir(service, child);
					}
				}));
			}
			
			for(Future<Long> partial : partials){
				total += partial.get(50, TimeUnit.SECONDS);
			}
		}
		return total;
	}
	
	public long getTotalSize(final String fileName) throws Exception{
		final ExecutorService service = Executors.newFixedThreadPool(100);
		try{
			return getTotalSizeOfFilesInDir(service, new File(fileName));
		}finally{
			service.shutdown();
		}
	}
	
	public static void main(String[] args)throws Exception{
		long start = System.nanoTime();
		String fileName = "D:\\mavenrepos\\repository\\org";
		long total = new NaiveConcurrentTotalFileSize().getTotalSize(fileName);
		long end = System.nanoTime();
		
		System.out.println("Total size: " + total);
		System.out.println("Time taken: " + (end - start)/1.0e9);
	}
}

